/******************************************************************************* * Copyright (c) 2008 - 2014 Red Hat, Inc. and others. * Distributed under license by Red Hat, Inc. All rights reserved. * This program is made available under the terms of the * Eclipse Public License v1.0 which accompanies this distribution, * and is available at http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Red Hat, Inc. - initial API and implementation ******************************************************************************/ package org.jboss.tools.ws.creation.core.commands; import java.util.ArrayList; import java.util.Iterator; import java.util.LinkedList; import java.util.List; import javax.wsdl.Port; import javax.wsdl.Service; import org.eclipse.core.commands.ExecutionException; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IAdaptable; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Status; import org.eclipse.jdt.core.ICompilationUnit; import org.eclipse.jdt.core.IJavaProject; import org.eclipse.jdt.core.IPackageFragment; import org.eclipse.jdt.core.IPackageFragmentRoot; import org.eclipse.jdt.core.JavaModelException; import org.eclipse.jdt.core.dom.AST; import org.eclipse.jdt.core.dom.ASTParser; import org.eclipse.jdt.core.dom.ArrayType; import org.eclipse.jdt.core.dom.Block; import org.eclipse.jdt.core.dom.BooleanLiteral; import org.eclipse.jdt.core.dom.CompilationUnit; import org.eclipse.jdt.core.dom.ImportDeclaration; import org.eclipse.jdt.core.dom.MemberValuePair; import org.eclipse.jdt.core.dom.MethodDeclaration; import org.eclipse.jdt.core.dom.Modifier; import org.eclipse.jdt.core.dom.Name; import org.eclipse.jdt.core.dom.NormalAnnotation; import org.eclipse.jdt.core.dom.NumberLiteral; import org.eclipse.jdt.core.dom.PackageDeclaration; import org.eclipse.jdt.core.dom.ParameterizedType; import org.eclipse.jdt.core.dom.PrimitiveType; import org.eclipse.jdt.core.dom.ReturnStatement; import org.eclipse.jdt.core.dom.SimpleName; import org.eclipse.jdt.core.dom.SimpleType; import org.eclipse.jdt.core.dom.SingleVariableDeclaration; import org.eclipse.jdt.core.dom.StringLiteral; import org.eclipse.jdt.core.dom.Type; import org.eclipse.jdt.core.dom.TypeDeclaration; import org.eclipse.jdt.core.dom.WildcardType; import org.eclipse.jface.dialogs.MessageDialog; import org.eclipse.jface.text.BadLocationException; import org.eclipse.jface.text.Document; import org.eclipse.text.edits.TextEdit; import org.eclipse.ui.PlatformUI; import org.eclipse.wst.common.frameworks.datamodel.AbstractDataModelOperation; import org.jboss.tools.ws.core.utils.StatusUtils; import org.jboss.tools.ws.creation.core.JBossWSCreationCorePlugin; import org.jboss.tools.ws.creation.core.data.ServiceModel; import org.jboss.tools.ws.creation.core.messages.JBossWSCreationCoreMessages; import org.jboss.tools.ws.creation.core.utils.JBossWSCreationUtils; public class ImplementationClassCreationCommand extends AbstractDataModelOperation { private static final String PREFIX_JAXWS_ANNOTATION_CLASS = "javax.jws"; //$NON-NLS-1$ private static final String DEFAULT_CU_SUFFIX = ".java"; //$NON-NLS-1$ private static final String ANNOTATION_WEB_SERVICE_FULLNAME = "javax.jws.WebService"; //$NON-NLS-1$ private static final String ANNOTATION_TYPE_NAME_WEBSERVICE = "WebService";; //$NON-NLS-1$ private static final String ANNOTATION_PROPERTY_SERVICE_NAME = "serviceName"; //$NON-NLS-1$ private static final String ANNOTATION_PROPERTY_ENDPOINT_INTERFACE = "endpointInterface"; //$NON-NLS-1$ private static final String ANNOTATION_PROPERTY_TNS = "targetNamespace"; //$NON-NLS-1$ private static final String IMPL_PACKAGE = ".impl"; //$NON-NLS-1$ public static final String LINE_SEPARATOR = System.getProperty("line.separator"); //$NON-NLS-1$ private ServiceModel model; private IJavaProject project; private String packageName; private String serviceName; private String targetNamespace; public ImplementationClassCreationCommand(ServiceModel model) { this.model = model; } @Override public IStatus execute(IProgressMonitor monitor, IAdaptable info) throws ExecutionException { IStatus status = Status.OK_STATUS; // if the user does not check the generate implementation class button, // do nothing if (!model.isGenImplementation()) { return status; } project = model.getJavaProject(); packageName = model.getCustomPackage(); List<ICompilationUnit> portTypeUnits = JBossWSCreationUtils .findJavaUnitsByAnnotation(project, JBossWSCreationCoreMessages.Webservice_Annotation, packageName); if (portTypeUnits.size() == 0 ) { return status; } packageName = portTypeUnits.get(0).getParent().getElementName() + IMPL_PACKAGE; IPackageFragment pack = null; try { pack = createImplPackage(packageName); } catch (JavaModelException e1) { status = StatusUtils.errorStatus(JBossWSCreationCoreMessages.Error_Message_Failed_to_Generate_Implementation,e1); return status; } Service service = model.getService(); serviceName = service.getQName().getLocalPart(); targetNamespace = model.getWsdlDefinition().getTargetNamespace(); Iterator<?> iter = service.getPorts().values().iterator(); List<String> ptList = new LinkedList<String>(); while (iter.hasNext()) { Port port = (Port) iter.next(); ptList.add(port.getBinding().getPortType().getQName().getLocalPart().toLowerCase()); } boolean isOverWrite = false; try { for (ICompilationUnit portType : portTypeUnits) { if (!portType.findPrimaryType().isInterface()) { continue; } String clsName = getClassName(portType.getElementName()); String implClsName = getImplClassName(clsName); if (!ptList.contains(clsName.toLowerCase())) { continue; } if (!isOverWrite && findImplClass(implClsName)) { if (!isOverwriteClass()) { break; } isOverWrite = true; } generateImplClass(portType, pack, clsName, implClsName); model.addServiceClasses(new StringBuffer(packageName).append(".").append(implClsName).toString()); //$NON-NLS-1$ } } catch (CoreException e) { status = StatusUtils .errorStatus( JBossWSCreationCoreMessages.Error_Message_Failed_to_Generate_Implementation, e); JBossWSCreationCorePlugin.getDefault().logError(e); } catch (BadLocationException e) { status = StatusUtils .errorStatus( JBossWSCreationCoreMessages.Error_Message_Failed_to_Generate_Implementation, e); JBossWSCreationCorePlugin.getDefault().logError(e); } return status; } @SuppressWarnings("unchecked") protected void generateImplClass(ICompilationUnit portType, IPackageFragment pack, String ptCls, String clsName) throws CoreException, BadLocationException { ASTParser astp = ASTParser.newParser(AST.JLS3); astp.setKind(ASTParser.K_COMPILATION_UNIT); astp.setSource(portType); CompilationUnit cu = (CompilationUnit) astp.createAST(null); String implFileName = getJavaFileName(clsName); ICompilationUnit icu = pack.createCompilationUnit(implFileName,"", true, null); //$NON-NLS-1$ // create a working copy with a new owner icu.becomeWorkingCopy(null); ASTParser parser = ASTParser.newParser(AST.JLS3); parser.setSource(icu); parser.setResolveBindings(false); parser.setFocalPosition(0); CompilationUnit implCu = (CompilationUnit) parser.createAST(null); AST ast = implCu.getAST(); // creation of a Document and ASTRewrite String source = icu.getBuffer().getContents(); Document document = new Document(source); implCu.recordModifications(); // start to add content into implementation class // add package declaration for impl class: PackageDeclaration implPackage = ast.newPackageDeclaration(); implPackage.setName(ast.newName(pack.getElementName())); implCu.setPackage(implPackage); // add imports for implementation class addImportsToImplementationClass(implCu, cu, ptCls); // add class declaration TypeDeclaration type = ast.newTypeDeclaration(); type.setInterface(false); // add WebService annotation String endpoint = getPortTypeFullName(portType.getParent().getElementName(), ptCls); NormalAnnotation ann = null; if (serviceName != null) { ann = createAnnotation(ast, serviceName, endpoint, targetNamespace); } else { ann = createAnnotation(ast, clsName, endpoint, targetNamespace); } type.modifiers().add(ann); type.modifiers().add(ast.newModifier(Modifier.ModifierKeyword.PUBLIC_KEYWORD)); type.setName(ast.newSimpleName(clsName)); type.superInterfaceTypes().add(ast.newSimpleType(ast.newName(ptCls))); // add Logger variable declaration // createLoggerField(ast, type, portTypeName); // add method implementation TypeDeclaration inTD = (TypeDeclaration) cu.types().get(0); // firstly, get all methods that declared in Interface class and then // add corresponding methods to // the impl class MethodDeclaration[] methods = inTD.getMethods(); for (int i = 0; i < methods.length; i++) { MethodDeclaration newMethod = createMethodForImplClass(ast, methods[i]); type.bodyDeclarations().add(newMethod); } implCu.types().add(type); // try to save the Java file TextEdit edits = implCu.rewrite(document, icu.getJavaProject() .getOptions(true)); edits.apply(document); String newSource = document.get(); icu.getBuffer().setContents(newSource); icu.reconcile(ICompilationUnit.NO_AST, false, null, null); icu.commitWorkingCopy(true, null); icu.discardWorkingCopy(); } private String getImplPackageName() { return packageName; } private String getJavaFileName(String className) { return className + DEFAULT_CU_SUFFIX; } private String getImplClassName(String className) { return className + "Impl"; //$NON-NLS-1$ } private String getClassName(String className) { String clsName = className.substring(0, className.length() - 5); return clsName; } private String getPortTypeFullName(String packageName, String className) { return packageName + "." + className; //$NON-NLS-1$ } @SuppressWarnings("unchecked") private void addImportsToImplementationClass(CompilationUnit implCU, CompilationUnit serviceCU, String serviceName) { List<ImportDeclaration> imports = getImportsWithoutJaxwsAnnotation(serviceCU); AST implAST = implCU.getAST(); // add imports for implementation class for (ImportDeclaration id : imports) { ImportDeclaration newId = implAST.newImportDeclaration(); newId.setName(implAST.newName(id.getName().getFullyQualifiedName())); implCU.imports().add(newId); } // import port type interface ImportDeclaration importDec = implAST.newImportDeclaration(); importDec.setName(implAST.newName(serviceCU.getPackage().getName().toString())); importDec.setOnDemand(true); implCU.imports().add(importDec); // importDec = implAST.newImportDeclaration(); // importDec.setName(implAST.newName(LOGGER_CLASS_FULLNAME)); // implCU.imports().add(importDec); // import jaxws WebService importDec = implAST.newImportDeclaration(); // hardcode here? importDec.setName(implAST.newName(ANNOTATION_WEB_SERVICE_FULLNAME)); implCU.imports().add(importDec); } /* * create web service annotation */ @SuppressWarnings("unchecked") protected NormalAnnotation createAnnotation(AST ast, String serviceName, String endpoint, String targetNamespace) { NormalAnnotation ann = ast.newNormalAnnotation(); ann.setTypeName(ast.newSimpleName(ANNOTATION_TYPE_NAME_WEBSERVICE)); MemberValuePair member = createMemberValuePair(ast, ANNOTATION_PROPERTY_SERVICE_NAME, serviceName); ann.values().add(member); member = createMemberValuePair(ast, ANNOTATION_PROPERTY_ENDPOINT_INTERFACE, endpoint); ann.values().add(member); if (targetNamespace != null) { member = createMemberValuePair(ast, ANNOTATION_PROPERTY_TNS, targetNamespace); ann.values().add(member); } return ann; } private MemberValuePair createMemberValuePair(AST ast, String propertyName, String Value) { MemberValuePair member = ast.newMemberValuePair(); member.setName(ast.newSimpleName(propertyName)); StringLiteral value = ast.newStringLiteral(); value.setLiteralValue(Value); member.setValue(value); return member; } @SuppressWarnings("unchecked") protected MethodDeclaration createMethodForImplClass(AST ast, MethodDeclaration inMethod) { MethodDeclaration md = ast.newMethodDeclaration(); md.setConstructor(false); @SuppressWarnings("rawtypes") List modifiers = md.modifiers(); modifiers.add(ast.newModifier(Modifier.ModifierKeyword.PUBLIC_KEYWORD)); md.setName(ast .newSimpleName(inMethod.getName().getFullyQualifiedName())); Type sType = copyTypeFromOtherASTNode(ast, inMethod.getReturnType2()); md.setReturnType2(sType); @SuppressWarnings("rawtypes") List thrownExceptions = inMethod.thrownExceptions(); for (Object obj : thrownExceptions) { if (obj instanceof SimpleName) { SimpleName sname = (SimpleName) obj; Name newName = ast.newName(sname.getFullyQualifiedName()); md.thrownExceptions().add(newName); } } @SuppressWarnings("rawtypes") List parameters = inMethod.parameters(); for (Object obj : parameters) { SingleVariableDeclaration implSvd = ast .newSingleVariableDeclaration(); SingleVariableDeclaration svd = (SingleVariableDeclaration) obj; implSvd.setName(ast.newSimpleName(svd.getName() .getFullyQualifiedName())); implSvd.setType(copyTypeFromOtherASTNode(ast, svd.getType())); md.parameters().add(implSvd); } // create method body Block block = ast.newBlock(); // add log info statement // block.statements().add(createLoggerInvokeStatement(ast, // md.getName().getFullyQualifiedName())); Type returnType = inMethod.getReturnType2(); ReturnStatement rs = ast.newReturnStatement(); if (returnType.isPrimitiveType()) { if (((PrimitiveType) returnType).getPrimitiveTypeCode().equals( PrimitiveType.BOOLEAN)) { BooleanLiteral bl = ast.newBooleanLiteral(false); rs.setExpression(bl); } else if (!((PrimitiveType) returnType).getPrimitiveTypeCode() .equals(PrimitiveType.VOID)) { NumberLiteral nl = ast.newNumberLiteral(); nl.setToken("0"); //$NON-NLS-1$ rs.setExpression(nl); } } else if (returnType.isSimpleType()) { String typeName = ((SimpleType) returnType).getName() .getFullyQualifiedName(); if ("String".equals(typeName)) { //$NON-NLS-1$ StringLiteral sl = ast.newStringLiteral(); sl.setLiteralValue(""); //$NON-NLS-1$ rs.setExpression(sl); } else { rs.setExpression(ast.newNullLiteral()); } } else { rs.setExpression(ast.newNullLiteral()); } block.statements().add(rs); md.setBody(block); return md; } @SuppressWarnings("unchecked") private Type copyTypeFromOtherASTNode(AST ast, Type type) { if (type instanceof PrimitiveType) { return ast.newPrimitiveType(((PrimitiveType) type) .getPrimitiveTypeCode()); } else if (type instanceof SimpleType) { SimpleType simpleType = (SimpleType) type; return ast.newSimpleType(ast.newName(simpleType.getName() .getFullyQualifiedName())); } else if (type instanceof ArrayType) { ArrayType atype = (ArrayType) type; return ast.newArrayType(copyTypeFromOtherASTNode(ast, atype.getComponentType())); } else if (type instanceof ParameterizedType) { ParameterizedType ptype = (ParameterizedType) type; ParameterizedType newParaType = ast .newParameterizedType(copyTypeFromOtherASTNode(ast, ptype.getType())); for (Object arg : ptype.typeArguments()) { if (arg instanceof Type) { Type newArg = copyTypeFromOtherASTNode(ast, (Type) arg); newParaType.typeArguments().add(newArg); } } return newParaType; } else if (type instanceof WildcardType) { WildcardType sourcetype = (WildcardType) type; WildcardType wtype = ast.newWildcardType(); wtype.setBound(sourcetype.getBound()); return wtype; } return null; } private IPackageFragment createImplPackage(String implPackage) throws JavaModelException { IPackageFragmentRoot root = JBossWSCreationUtils.getPackageFragmentRoot(project, model.getJavaSourceFolder()); return root.createPackageFragment(implPackage,false, null); } private boolean isOverwriteClass() throws JavaModelException { boolean b = MessageDialog .openConfirm(PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell(), JBossWSCreationCoreMessages.Confirm_Override_ImplClass, JBossWSCreationCoreMessages.Error_JBossWS_GenerateWizard_WSImpl_Overwrite); return b; } private boolean findImplClass(String claName) throws JavaModelException { boolean b = false; IPackageFragmentRoot root = JBossWSCreationUtils.getPackageFragmentRoot(project, model.getJavaSourceFolder()); String implPackageName = getImplPackageName(); IPackageFragment pack = root.getPackageFragment(implPackageName); if (pack.getCompilationUnit(claName + ".java").exists()) { //$NON-NLS-1$ b = true; } return b; } protected List<ImportDeclaration> getImportsWithoutJaxwsAnnotation( CompilationUnit cu) { List<ImportDeclaration> importList = new ArrayList<ImportDeclaration>(); @SuppressWarnings("rawtypes") List imports = cu.imports(); for (Object obj : imports) { ImportDeclaration id = (ImportDeclaration) obj; String imClsName = id.getName().getFullyQualifiedName(); if (!imClsName.startsWith(PREFIX_JAXWS_ANNOTATION_CLASS)) { importList.add(id); } } return importList; } }